import {
  ConflictException,
  Injectable,
  InternalServerErrorException,
  NotFoundException,
} from '@nestjs/common';
import { CreateMenuDto } from './dto/create-menu.dto';
import { UpdateMenuDto } from './dto/update-menu.dto';
import { EntityManager, Repository } from 'typeorm';
import { Menu } from './entities/menu.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from '../user/entities/user.entity';
import { ThemeFilterDto } from '../theme/dto/themeFilterDto';
import { IPaginationOptions, paginate, Pagination } from '../utils/paginate';
import { Role } from '../role/entities/role.entity';
import { BindRoleDto } from './dto/bind-role.dto';

@Injectable()
export class MenuService {
  constructor(
    @InjectRepository(Menu) private repository: Repository<Menu>,
    private entityManage: EntityManager,
  ) {}

  async create(createMenuDto: CreateMenuDto, user: User): Promise<string> {
    createMenuDto.user = user;
    const menu = this.repository.create(createMenuDto);
    try {
      await this.repository.save(menu);
    } catch (error) {
      if (error.code === '23505' || error.code === 'ER_DUP_ENTRY') {
        // 重复用户名
        throw new ConflictException(`该数据'${menu.name}'已存在！`);
      } else {
        throw new InternalServerErrorException('内部服务器错误异常');
      }
    }
    if (createMenuDto.parentId) {
      await this.bindTree(createMenuDto.parentId, createMenuDto.name);
    }
    return '创建成功！';
  }

  /**
   *
   * @param parentId parentId
   * @param name children name
   * @param id children id
   * @param user userInfo
   */
  async bindTree(
    parentId: string,
    name?: string,
    id?: string,
    user?: User,
  ): Promise<string> {
    let children;
    if (name) {
      children = await this.repository.findOneBy({ name });
    } else {
      children = await this.repository.findOneBy({ id });
    }
    children.parent = await this.repository.findOneBy({ id: parentId });
    children.updateUser = user;
    await this.repository.save(children);
    return '绑定成功！';
  }
  async findAll(
    data: ThemeFilterDto,
    options: IPaginationOptions,
  ): Promise<Pagination<Menu>> {
    const { search: name } = data;
    const menu = this.entityManage
      .getRepository(Menu)
      .createQueryBuilder('menu');
    if (name) {
      menu.where(
        '(LOWER(menu.name) LIKE LOWER(:name) OR LOWER(menu.title) LIKE LOWER(:name))',
        { name: `%${name}%` },
      );
    }
    const menus = await menu.andWhere('menu.isDelete = 0');
    return paginate<Menu>(menus, options);
  }
  async findAllTree(): Promise<Menu[]> {
    const dataTree = await this.entityManage
      .getTreeRepository(Menu)
      .findTrees();
    return dataTree;
  }
  async findOne(id: string): Promise<Menu> {
    // const menu = await this.repository.findOneBy({ id, isDelete: 0 });
    const menu = await this.repository
      .createQueryBuilder('menu')
      .where('menu.id = :id and menu.isDelete = 0', { id: id })
      .getOne();
    const menuTree = await this.entityManage
      .getTreeRepository(Menu)
      .findDescendantsTree(menu);
    if (!menuTree) {
      throw new NotFoundException(`参数${id}没有找到！`);
    }
    return menuTree;
  }

  async update(updateMenuDto: UpdateMenuDto, user: User): Promise<string> {
    // updateMenuDto.updateUser = user;
    const {
      id,
      name,
      routePath,
      permissions,
      redirect,
      keepalive,
      isHidden,
      isDelete,
      iconSvg,
      icon,
      type,
      component,
      title,
      fixed,
      sort,
    } = updateMenuDto;
    let parent = null;
    if (updateMenuDto.parentId) {
      parent = await this.repository.findOneBy({
        id: updateMenuDto.parentId,
      });
    }
    await this.repository
      .createQueryBuilder('menu')
      .update(Menu)
      .set({
        id,
        name,
        parent,
        isDelete,
        iconSvg,
        icon,
        type,
        component,
        title,
        fixed,
        sort,
        isHidden,
        keepalive,
        permissions,
        redirect,
        updateUser: user,
        routePath,
      })
      .where('id = :id', { id: updateMenuDto.id })
      .execute();
    return `修改成功！`;
  }

  async remove(id: string): Promise<string> {
    const result = await this.repository.delete({ id });
    if (result.affected === 0) {
      throw new NotFoundException(`参数 ${id} 没有找到！`);
    }
    return `删除成功!`;
  }

  async bindRoles(data: BindRoleDto): Promise<string> {
    const { roleId, menuIds } = data;
    const menu = [];
    for (const item of menuIds) {
      const data = await this.findOne(item);
      if (data) {
        menu.push(data);
      }
    }
    const role = await this.entityManage
      .getRepository(Role)
      .findOneBy({ id: roleId });
    role.menu = menu;
    await this.entityManage.getRepository(Role).save(role);
    return '绑定成功！';
  }
}
